package com.opages.mvc.adapter.common.condition;

import com.opages.mvc.adapter.common.autoconfigure.AutoConfigurationImportFilter;
import com.opages.mvc.adapter.common.autoconfigure.AutoConfigurationMetadata;
import com.opages.mvc.adapter.common.condition.core.ConditionOutcome;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @author daizhong.liu
 * @create 2020-07-10 9:20
 **/
abstract class FilteringCondition extends AnnotationCondition implements AutoConfigurationImportFilter, BeanClassLoaderAware {
    private ClassLoader beanClassLoader;

    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        //回调子类实现getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
        //匹配说明指定类存在，则允许注入容器
        ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
        boolean[] match = new boolean[outcomes.length];
        for (int i = 0; i < outcomes.length; i++) {
            //匹配（说明调用MISS进行匹配）或空表示允许
            match[i] = (outcomes[i] == null || outcomes[i].isMatch());
        }
        return match;
    }

    protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);

    protected final ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.beanClassLoader = classLoader;
    }
    //过滤出指定匹配是否存在的类列表
    protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter, ClassLoader classLoader) {
        if (CollectionUtils.isEmpty(classNames)) {
            return Collections.emptyList();
        }
        List<String> matches = new ArrayList<>(classNames.size());
        for (String candidate : classNames) {
            if (classNameFilter.matches(candidate, classLoader)) {
                matches.add(candidate);
            }
        }
        return matches;
    }
    //根据类名,反射出class类
    protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
        if (classLoader != null) {
            return Class.forName(className, false, classLoader);
        }
        return Class.forName(className);
    }
    //类型过滤器,判断指定全路径类名是否存在
    protected enum ClassNameFilter {
        /**
         * 该全路径类名存在为true
         */

        PRESENT {
            @Override
            public boolean matches(String className, ClassLoader classLoader) {
                return isPresent(className, classLoader);
            }

        },
        /**
         * 该全路径类名不存在为true
         */

        MISSING {
            @Override
            public boolean matches(String className, ClassLoader classLoader) {
                return !isPresent(className, classLoader);
            }
        };
        //匹配是否存在,由子类实现
        abstract boolean matches(String className, ClassLoader classLoader);
        //是否存在
        static boolean isPresent(String className, ClassLoader classLoader) {
            if (classLoader == null) {
                classLoader = ClassUtils.getDefaultClassLoader();
            }
            try {
                resolve(className, classLoader);
                return true;
            }
            catch (Throwable ex) {
                return false;
            }
        }

    }
}
